package cert

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"github.com/caddyserver/certmagic"
	"io"
	"log"
	"os"
	"path/filepath"
	"time"
)

// 初始化证书管理
func InitCertMagic(email, certdir string) error {
	// 配置certmagic
	certmagic.DefaultACME.Agreed = true
	certmagic.DefaultACME.Email = email
	certmagic.DefaultACME.CA = certmagic.LetsEncryptProductionCA

	// 设置证书存储路径
	if err := os.MkdirAll(certdir, 0755); err != nil {
		return fmt.Errorf("failed to create cert directory: %v", err)
	}

	// 配置存储
	certmagic.Default.Storage = &certmagic.FileStorage{Path: certdir}
	return nil
}

// 检查证书是否需要续期（建议在证书过期前30天续期）
func NeedsRenewal(certPath, keyPath string) bool {
	cert, err := tls.LoadX509KeyPair(certPath, keyPath)
	if err != nil {
		log.Printf("Failed to load certificate: %v, certPath: %s, keyPath: %s", err, certPath, keyPath)
		return true // 证书加载失败，需要重新申请
	}

	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
	if err != nil {
		log.Printf("Failed to parse certificate: %v, certPath: %s, keyPath: %s", err, certPath, keyPath)
		return true
	}

	log.Printf("Certificate expires at: %s", x509Cert.NotAfter.Format("2006-01-02 15:04:05"))
	daysLeft := int(time.Until(x509Cert.NotAfter).Hours() / 24)
	if daysLeft > 0 {
		log.Printf("Certificate expires in %d days", daysLeft)
	} else {
		log.Printf("WARNING: Certificate has expired %d days ago!", -daysLeft)
	}
	renewalTime := x509Cert.NotAfter.Add(-20 * 24 * time.Hour)
	return time.Now().After(renewalTime)
}

// 获取证书
func ObtainCertificate(certdir string, domain string) error {
	// 先检查是否已有有效证书
	certPath, keyPath, err := GetCertPaths(certdir, domain)

	if err == nil {
		// 检查证书是否存在且有效
		if _, errPT := os.Stat(certPath); errPT == nil {
			if _, errKT := os.Stat(keyPath); errKT == nil {
				// 检查证书有效期
				if !NeedsRenewal(certPath, keyPath) {
					log.Printf("Valid certificate already exists for domain: %s", domain)
					return nil
				}
			} else {
				log.Printf("Key file does not exist for domain: %s", domain)
			}
		} else {
			log.Printf("Certificate file does not exist for domain: %s", domain)
		}
	}

	log.Printf("Obtaining certificate for domain: %s", domain)
	ctx := context.Background()
	err = certmagic.ManageSync(ctx, []string{domain})
	if err != nil {
		return fmt.Errorf("failed to obtain certificate: %v", err)
	}

	time.Sleep(2 * time.Second)
	certPath = filepath.Join(certdir, "certificates", "acme-v02.api.letsencrypt.org-directory", domain, domain+".crt")
	keyPath = filepath.Join(certdir, "certificates", "acme-v02.api.letsencrypt.org-directory", domain, domain+".key")

	// Copy certificate file
	certSrc, err := os.Open(certPath)
	if err != nil {
		return fmt.Errorf("failed to open certificate file: %v", err)
	}
	defer certSrc.Close()

	certDst, err := os.Create(filepath.Join(certdir, domain+".crt"))
	if err != nil {
		return fmt.Errorf("failed to create certificate file: %v", err)
	}
	defer certDst.Close()

	_, err = io.Copy(certDst, certSrc)
	if err != nil {
		return fmt.Errorf("failed to copy certificate file: %v", err)
	}

	// Copy key file
	keySrc, err := os.Open(keyPath)
	if err != nil {
		return fmt.Errorf("failed to open key file: %v", err)
	}
	defer keySrc.Close()

	keyDst, err := os.Create(filepath.Join(certdir, domain+".key"))
	if err != nil {
		return fmt.Errorf("failed to create key file: %v", err)
	}
	defer keyDst.Close()

	_, err = io.Copy(keyDst, keySrc)
	if err != nil {
		return fmt.Errorf("failed to copy key file: %v", err)
	}
	//删除旧证书
	DeleteCert(certdir)

	log.Printf("Certificate obtained successfully for domain: %s", domain)
	return nil
}

// 获取证书文件路径
func GetCertPaths(certDir string, domain string) (string, string, error) {
	certFile := filepath.Join(certDir, domain+".crt")
	keyFile := filepath.Join(certDir, domain+".key")

	// 检查证书文件是否存在
	if _, err := os.Stat(certFile); os.IsNotExist(err) {
		return "", "", fmt.Errorf("certificate file not found: %s", certFile)
	}
	if _, err := os.Stat(keyFile); os.IsNotExist(err) {
		return "", "", fmt.Errorf("key file not found: %s", keyFile)
	}

	return certFile, keyFile, nil
}

// 删除证书文件
func DeleteCert(certDir string) {
	os.RemoveAll(filepath.Join(certDir, "certificates"))
	os.RemoveAll(filepath.Join(certDir, "acme"))
	os.RemoveAll(filepath.Join(certDir, "locks"))
}

//删除
